# -*- coding: utf-8 -*-
"""
Created on Sun May  3 16:16:05 2020

@author: RaingEye
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import time
import os

import warnings
warnings.filterwarnings('ignore')
#不发出警告

from bokeh.plotting import figure, show, output_file
from bokeh.models import ColumnDataSource, HoverTool
#导图绘图模块

'''
(1) 第一轮模拟
'''
def create_sample(n, gender):
    sample_data = pd.DataFrame({'fortune':np.random.exponential(scale = 15, size = n) + 45,
                                'apperance': np.random.normal(loc = 60, scale = 15, size = n),
                                'character': np.random.normal(loc = 60, scale = 15, size = n)},
                                index = [gender + str(i) for i in range(1, n+1)])
    sample_data.index.name = 'id'
    sample_data['score'] = sample_data.sum(axis = 1)/3
    return sample_data

#sample_m_test = create_sample(99, 'm')
#sample_f_test = create_sample(99, 'f')
#sample_m_test['strategy'] = np.random.choice([1, 2, 3], 99)
#创建样本数据

match_success = pd.DataFrame(columns = ['m', 'f', 'round_n', 'strategy_type'])
#创建空数据集，分别是男性编号、女性编号、第几轮、哪个策略

#round1_f = sample_f_test.copy()
#round1_m = sample_m_test.copy()
##复制实验数据，创建实验副本
#
#round1_m['choice'] = np.random.choice(round1_f.index, len(round1_m))
##该轮的匹配选择，根据男性数量选择女性数量
#round1_match = pd.merge(round1_m, round1_f, left_on = 'choice', right_index = True).reset_index()
#
#round1_match['score_dis'] = np.abs(round1_match['score_x'] - round1_match['score_y'])   #就散综合评分差值
#round1_match['cha_dis'] = np.abs(round1_match['character_x'] - round1_match['character_y']) #计算内涵评分差值
#round1_match['for_dis'] = np.abs(round1_match['fortune_x'] - round1_match['fortune_y']) #计算财富评分差值
#round1_match['app_dis'] = np.abs(round1_match['apperance_x'] - round1_match['apperance_y']) #计算外貌评分差值

#合并数据



#策略1：门当户对
#round1_s1_m = round1_match[round1_match['strategy'] == 1]
#round1_s1_success = round1_s1_m[round1_s1_m['score_dis'] <= 20].groupby('choice').max()
#round1_s1_success = pd.merge(round1_s1_success, round1_m.reset_index(), left_on = 'score_x', right_on = 'score')[['id_y', 'choice']]
#
#round1_s1_success.columns = ['m','f']
#round1_s1_success['strategy_type'] = 1
#round1_s1_success['round_n'] = 1    #成功得到策略1的匹配结果
#
#
#round1_match.index = round1_match['choice']
#round1_match = round1_match.drop(round1_s1_success['f'].tolist())
##由于在之前，一个女性可能匹配多个男性，所有当删除匹配成功的数据后，除了删掉了相应匹配成功的男性，同样也删除了竞争失败的男性
#
#
#'''
#策略2：郎才女貌
#'''
#round1_s2_m = round1_match[round1_match['strategy'] == 2]
#round1_s2_success = round1_s2_m[(round1_s2_m['fortune_x'] - round1_s2_m['fortune_y']>=10)
#                                &(round1_s2_m['apperance_y'] - round1_s2_m['apperance_x'] >= 10)]
#round1_s2_success = round1_s2_success.groupby('choice').max()
#round1_s2_success = pd.merge(round1_s2_success, round1_m.reset_index(), left_on = 'score_x', right_on = 'score')[['id_y','choice']]
#round1_s2_success = round1_s2_success[['id_y','choice']]
#round1_s2_success.columns = ['m', 'f']
#round1_s2_success['strategy_type'] = 2
#round1_s2_success['round_n'] = 1
#round1_match.index = round1_match['choice']
#round1_match = round1_match.drop(round1_s2_success['f'].tolist())
#
#
#'''
#策略3：志趣相投、适度引领
#'''
#round1_s3_m = round1_match[round1_match['strategy'] == 3]
#round1_s3_success = round1_s3_m[(round1_s3_m['cha_dis'] <10) &   # 内涵得分差在10分以内\n",
#                                   (round1_s3_m['for_dis'] < 5 )&    # 财富得分差在5分以内\n",
#                                  (round1_s3_m['app_dis'] < 5 )]    # 外貌得分差在5分以内\n",
#round1_s3_success = round1_s3_success.groupby('choice').max()                                      # 筛选符合要求的数据\n",
#round1_s3_success = pd.merge(round1_s3_success,round1_m.reset_index(),left_on = 'score_x',right_on = 'score')[['id_y','choice']]
#round1_s3_success.columns = ['m','f']
#round1_s3_success['strategy_type'] = 3
#round1_s3_success['round_n'] = 1
#
## 筛选出成功匹配数据
#match_success = pd.concat([match_success,round1_s1_success,round1_s2_success,round1_s3_success])    
#
##筛选出下一轮的实验数据
#round2_m = round1_m.drop(match_success['m'].tolist())
#round2_f = round1_f.drop(match_success['f'].tolist())

'''
构建模型
'''
def different_strategy(data_m, data_f, roundnum):
    data_m['choice'] = np.random.choice(data_f.index, len(data_m))
    #该轮匹配的选择
    
    round_match = pd.merge(data_m, data_f, left_on = 'choice', right_index = True).reset_index()
    #合并数据
    round_match['score_dis'] = np.abs(round_match['score_x'] - round_match['score_y'])  #计算综合评分差值
    round_match['cha_dis'] = np.abs(round_match['character_x'] - round_match['character_y']) #计算内涵评分差值
    round_match['for_dis'] = np.abs(round_match['fortune_x'] - round_match['fortune_y']) #计算财富评分差值
    round_match['app_dis'] = np.abs(round_match['apperance_x'] - round_match['apperance_y']) #计算外貌评分差值
    #计算各个指标差值
    
    #策略1：门当户对
    s1_m = round_match[round_match['strategy'] == 1]
    s1_success = s1_m[s1_m['score_dis'] <= 20].groupby('choice').max()
    s1_success = pd.merge(s1_success, data_m.reset_index(), left_on = 'score_x', right_on = 'score')[['id_y', 'choice']]
    
    s1_success.columns = ['m','f']
    s1_success['strategy_type'] = 1
    s1_success['round_n'] = roundnum    #成功得到策略1的匹配结果    
    round_match.index = round_match['choice']
    round_match = round_match.drop(s1_success['f'].tolist())
    #由于在之前，一个女性可能匹配多个男性，所有当删除匹配成功的数据后，除了删掉了相应匹配成功的男性，同样也删除了竞争失败的男性
    
    
    '''
    策略2：郎才女貌
    '''
    s2_m = round_match[round_match['strategy'] == 2]
    s2_success = s2_m[(s2_m['fortune_x'] - s2_m['fortune_y']>=10)
                                    &(s2_m['apperance_y'] - s2_m['apperance_x'] >= 10)]
    s2_success = s2_success.groupby('choice').max()
    s2_success = pd.merge(s2_success, data_m.reset_index(), left_on = 'score_x', right_on = 'score')[['id_y','choice']]
    s2_success = s2_success[['id_y','choice']]
    s2_success.columns = ['m', 'f']
    s2_success['strategy_type'] = 2
    s2_success['round_n'] = roundnum
    round_match.index = round_match['choice']
    round_match = round_match.drop(s2_success['f'].tolist())
    
    
    '''
    策略3：志趣相投、适度引领
    '''
    s3_m = round_match[round_match['strategy'] == 3]
    s3_success = s3_m[(s3_m['cha_dis'] <10) &   # 内涵得分差在10分以内\n",
                                       (s3_m['for_dis'] < 5 )&    # 财富得分差在5分以内\n",
                                      (s3_m['app_dis'] < 5 )]    # 外貌得分差在5分以内\n",
    s3_success = s3_success.groupby('choice').max()                                      # 筛选符合要求的数据\n",
    s3_success = pd.merge(s3_success,data_m.reset_index(),left_on = 'score_x',right_on = 'score')[['id_y','choice']]
    s3_success.columns = ['m','f']
    s3_success['strategy_type'] = 3
    s3_success['round_n'] = roundnum
    
    #该轮成功匹配数据
    data_success = pd.concat([s1_success, s2_success, s3_success])
    return data_success

'''
运行模型
'''
sample1_m1 = create_sample(10000, 'm')
sample1_f1 = create_sample(10000, 'f')
sample1_m1['strategy'] = np.random.choice([1, 2, 3], 10000)
#创建样本数据    

test_m1 = sample1_m1.copy()
test_f1 = sample1_f1.copy()
#复制实验数据，创建实验副本

n = 1
#设置一个实验次数变量

starttime = time.time()
#设置起始时间

success_roundn = different_strategy(test_m1, test_f1, n)
match_success1 = success_roundn
test_m1 = test_m1.drop(success_roundn['m'].tolist())
test_f1 = test_f1.drop(success_roundn['f'].tolist())

print('成功进行第%i轮试验，本轮实验成功匹配%i对，总共成功匹配%i对，还剩下%i位男性和%i为女性'%
      (n, len(success_roundn), len(match_success1), len(test_m1),len(test_f1)))
#第一轮测试


while len(success_roundn) != 0:
    n += 1
    success_roundn = different_strategy(test_m1,test_f1,n)   
    #得到该轮成功匹配数据
    match_success1 = pd.concat([match_success1,success_roundn])           
    # 将成功匹配数据汇总
    test_m1 = test_m1.drop(success_roundn['m'].tolist())
    test_f1 = test_f1.drop(success_roundn['f'].tolist())
    # 输出下一轮实验数据
    print('成功进行第%i轮实验，本轮实验成功匹配%i对，总共成功匹配%i对，还剩下%i位男性和%i位女性' % 
          (n,len(success_roundn),len(match_success1),len(test_m1),len(test_f1)))

endtime = time.time()
#记录结束时间
print('--------------------')
print('本次实验总共进行了%i轮，配对成功%i对\n---------------'%(n, len(match_success1)))
print('实验总共耗时%.2f秒'%(endtime - starttime))


'''
(4)几个问题：
   百分之多少的样本数据成功匹配到了对象？
   采取不同择偶策略的匹配成功率分别是多少？
   采取不同择偶策略的男性各项平均分是多少？
'''
#百分之多少的样本数据成功匹配到了对象？
print('%.2f%%的样本数据成功许配到了对象\n-------------'%(len(match_success1)/len(sample1_m1)*100))

#采取不同择偶策略的匹配成功率分别是多少？
print('择偶策略1的匹配成功率为%.2f%%' % (len(match_success1[match_success1['strategy_type']==1])/len(sample1_m1[sample1_m1['strategy'] == 1])*100))
print('择偶策略2的匹配成功率为%.2f%%' % (len(match_success1[match_success1['strategy_type']==2])/len(sample1_m1[sample1_m1['strategy'] == 2])*100))
print('择偶策略3的匹配成功率为%.2f%%' % (len(match_success1[match_success1['strategy_type']==3])/len(sample1_m1[sample1_m1['strategy'] == 3])*100))
print('\n---------')

#采取不同择偶策略的男性各项平均分是多少？
match_m1 = pd.merge(match_success1,sample_m1,left_on = 'm',right_index = True)
result_df = pd.DataFrame([{'财富均值':match_m1[match_m1['strategy_type'] == 1]['fortune'].mean(),
                          '内涵均值':match_m1[match_m1['strategy_type'] == 1]['character'].mean(),
                          '外貌均值':match_m1[match_m1['strategy_type'] == 1]['apperance'].mean()},
                         {'财富均值':match_m1[match_m1['strategy_type'] == 2]['fortune'].mean(),
                          '内涵均值':match_m1[match_m1['strategy_type'] == 2]['character'].mean(),
                          '外貌均值':match_m1[match_m1['strategy_type'] == 2]['apperance'].mean()},
                         {'财富均值':match_m1[match_m1['strategy_type'] == 3]['fortune'].mean(),
                          '内涵均值':match_m1[match_m1['strategy_type'] == 3]['character'].mean(),
                          '外貌均值':match_m1[match_m1['strategy_type'] == 3]['apperance'].mean()}],
                         index = ['择偶策略1','择偶策略2','择偶策略3'])
# 构建数据dataframe
print('择偶策略1的男性 → 财富均值为%.2f，内涵均值为%.2f，外貌均值为%.2f' % 
      (result_df.loc['择偶策略1']['财富均值'],result_df.loc['择偶策略1']['内涵均值'],result_df.loc['择偶策略1']['外貌均值']))
print('择偶策略2的男性 → 财富均值为%.2f，内涵均值为%.2f，外貌均值为%.2f' % 
      (result_df.loc['择偶策略2']['财富均值'],result_df.loc['择偶策略2']['内涵均值'],result_df.loc['择偶策略2']['外貌均值']))
print('择偶策略3的男性 → 财富均值为%.2f，内涵均值为%.2f，外貌均值为%.2f' % 
      (result_df.loc['择偶策略3']['财富均值'],result_df.loc['择偶策略3']['内涵均值'],result_df.loc['择偶策略3']['外貌均值']))

